// stores/cesiumStore.js
import { defineStore } from 'pinia'
import { ref } from 'vue'
import * as Cesium from 'cesium'

export const useCesiumStore = defineStore('cesium', () => {
  // 状态
  const viewerCesium = ref(null)
  // 使用ES6类语法定义高德地图地理编码服务
  class AMapGeocoderService {
    geocode(input) {
      // 设置高德POI查询服务地址
      const endpoint = 'https://restapi.amap.com/v3/place/text?'
      let query = 'keywords=' + input //用户实际输入的搜索关键词
      query += '&output=json' //指定返回结果的格式为 JSON
      query += '&key=b8a40c7403ebc941de2d16aa88c8650c' //高德地图 API 密钥
      const requestString = endpoint + query

      // 使用Cesium.Resource.fetchJsonp来调用服务        fetchJsonp 使用 JSONP 请求资源
      return Cesium.Resource.fetchJsonp({ url: requestString })
        .then((results) => {
          // 检查是否有结果
          if (!results.pois || results.pois.length === 0) {
            console.log('地理搜索返回值无pois信息,', results)
            return []
          }
          console.log('高德地图搜索结果:', results)
          // 处理返回结果  //map()方法返回一个新数组，数组中的元素为原始数组调用函数处理后的值，并且按照原始数组元素调用函数处理后的值
          return results.pois.map((resultObject) => {
            return {
              //返回名字和地址
              displayName: resultObject.name + ' - ' + resultObject.address,
              //返回经纬度，并且转为笛卡尔3坐标
              destination: Cesium.Cartesian3.fromDegrees(
                +resultObject.location.split(',')[0],
                +resultObject.location.split(',')[1],
              ),
            }
          })
        })
        .catch((error) => {
          console.error('高德地图搜索服务出错:', error)
          return []
        })
    }
  }
  // 获取 影像视图模型组
  const getImageryProviderArr = () => {
    return [
      //每个项目的视图模型
      new Cesium.ProviderViewModel({
        // 图层的名称
        name: '图层一',
        // 当鼠标悬停在项目上时显示的工具提示。
        tooltip: '图层一',
        // 代表图层的图标
        iconUrl: '../../assets/images/icon/Logo_icon.png',
        // 一个函数或命令，用于创建一个或多个提供程序，这些提供程序将在选择此项目时添加到地球仪中
        creationFunction: () => {
          //.ArcGisMapServerImageryProvider 提供由ArcGIS MapServer托管的平铺图像
          return new Cesium.ArcGisMapServerImageryProvider({
            url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer',
          })
        },
      }),
      new Cesium.ProviderViewModel({
        // 图层的名称
        name: '图层二',
        // 显示项目被隐藏的工具提示
        tooltip: '图层二',
        // 代表图层的图标
        iconUrl: '../../assets/images/icon/Logo_icon.png',
        // 一个函数或命令，用于创建一个或多个提供程序，这些提供程序将在选择此项目时添加到地球仪中
        creationFunction: () => {
          return new Cesium.ArcGisMapServerImageryProvider({
            url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer',
          })
        },
      }),
    ]
  }
  //获取 地形视图模型组
  const getTerrainProviderViewModelsArr = () => {
    return [
      new Cesium.ProviderViewModel({
        // 图层的名称
        name: '无地形',
        // 显示项目被隐藏的工具提示
        tooltip: 'WGS84标准球体',
        // 代表图层的图标
        iconUrl: '../../assets/images/icon/Logo_icon.png',
        // 一个函数或命令，用于创建一个或多个提供程序，这些提供程序将在选择此项目时添加到地球仪中
        creationFunction: () => {
          //EllipsoidTerrainProvider  一个非常简单的 TerrainProvider，它通过曲面细分椭球体表面来生成几何体
          return new Cesium.EllipsoidTerrainProvider({
            //初始化为 WGS84 标准的 Ellipsoid 实例。
            ellipsoid: Cesium.Ellipsoid.WGS84,
          })
        },
      }),
      new Cesium.ProviderViewModel({
        // 图层的名称
        name: '地形',
        // 显示项目被隐藏的工具提示
        tooltip: 'STK在线地形',
        // 代表图层的图标
        iconUrl: '../../assets/images/icon/Logo_icon.png',
        // 一个函数或命令，用于创建一个或多个提供程序，这些提供程序将在选择此项目时添加到地球仪中
        creationFunction: () => {
          //CesiumTerrainProvider  一个 TerrainProvider，它以 Cesium 地形格式访问地形数据
          return new Cesium.CesiumTerrainProvider({
            //封装 Cesium ion 资产访问的 Resource 实例。  异步创建实例。 Cesium ion 资产 ID。
            url: Cesium.IonResource.fromAssetId(1), //Cesium 地形服务器的 URL
            requestWaterMask: true, //指示客户端是否应从服务器请求每个图块的水掩码（如果可用）的标志。
            requestVertexNormals: true, //指示客户端是否应以逐顶点法线的形式（如果可用）从服务器请求其他照明信息的标志。
          })
        },
      }),
    ]
  }

  // 初始化 Cesium Viewer
  const initViewerCesium = (containerId) => {
    //获取或设置默认的 Cesium ion 访问令牌。
    Cesium.Ion.defaultAccessToken =
      'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJhNGNhZTA5NC1mNjA1LTRhM2UtYmYxMi1hY2IyY2RjOTE4ZTEiLCJpZCI6MzA4NjE5LCJpYXQiOjE3NDg5MTUzMzd9.7icQyNIlJ826o81yrYhIG8RTDmNgC3TYRvR4XhNjhlA'

    //一、设置默认位置实现Home
    //#region
    //DEFAULT_VIEW_RECTANGLE相机将在创建时查看的默认矩形。homebutton默认跳转位置
    //Cesium.Rectangle指定为经度和纬度坐标的二维区域。
    //fromDegrees指定为经度和纬度坐标的二维区域(west西,south南,east东,north北)
    Cesium.Camera.DEFAULT_VIEW_RECTANGLE = Cesium.Rectangle.fromDegrees(90.5, 10.5, 135.5, 55.0) //90.5, 10.5, 135.5, 55.0
    //DEFAULT_VIEW_FACTOR一个标量，用于乘以摄像机位置，并在将摄像机设置为查看矩形后将其添加回来。值为零表示照相机将查看整个 Camera#DEFAULT_VIEW_RECTANGLE，
    //大于零的值会将其移离范围更远，小于零的值会将其移近范围。
    Cesium.Camera.DEFAULT_VIEW_FACTOR = 0.8
    //#endregion

    // addHours 将提供的小时数添加到提供的日期实例中。  (日期 ,要添加或减去的小时数。,用于结果的现有实例。 )
    // now 创建表示当前系统时间的新实例
    // 获取当前本地时间，并设置为北京时间（UTC+8）
    const now = Cesium.JulianDate.addHours(Cesium.JulianDate.now(), 8, new Cesium.JulianDate())

    // 替换 clockViewModel 初始化时的时间设置
    const clock = new Cesium.Clock({
      startTime: Cesium.JulianDate.clone(now),
      currentTime: Cesium.JulianDate.clone(now),
      stopTime: Cesium.JulianDate.addDays(now, 1, new Cesium.JulianDate()), // 第二天停止
      clockRange: Cesium.ClockRange.LOOP_STOP,
      clockStep: Cesium.ClockStep.SYSTEM_CLOCK_MULTIPLIER,
    })

    //初始化Viewer
    //#region
    //Viewer是用于构建应用程序的基础部件。
    //(container: id|HTMLElement(将容纳Viewer的HTML DOM 元素或ID。) , options: 配置项)
    viewerCesium.value = new Cesium.Viewer(containerId, {
      // geocoder  进行搜索时要使用的一个或多个地理编码服务
      // geocoder: new AMapGeocoderService(), //是否显示地名查找控件   // 使用自定义的高德地图地理编码服务
      geocoder: true,
      baseLayerPicker: true, //是否显示图层选择控件
      // 可从 BaseLayerPicker 中选择的 ProviderViewModels 数组。仅当 'baseLayerPicker' 设置为 true 时，此值才有效。
      // imageryProviderViewModels: getImageryProviderArr(), // //获取或设置可用于图像选择的ProviderViewModel实例数组。
      //可从 BaseLayerPicker 中选择的 ProviderViewModels 数组。仅当 'baseLayerPicker' 设置为 true 时，此值才有效
      // terrainProviderViewModels: getTerrainProviderViewModelsArr(), //获取或设置可用于地形选择的ProviderViewModel实例数组。
      homeButton: true, //是否显示home键
      sceneModePicker: true, //是否显示投影方式控件 2d 2.5d 3d  场景模式之间切换的单按钮控件
      shouldAnimate: true, // 自动播放// 如果 clock 默认应尝试提前 Simulation Time，则为 true，否则为 false。此选项优先于设置
      animation: true, //是否显示动画控件
      // 用于控制当前时间的 clock view 模型     一个视图模型，它为用户界面公开了一个 Clock
      clockViewModel: new Cesium.ClockViewModel(
        clock,
        // new Cesium.Clock({
        //   //.JulianDate儒略日数，表示整天数。小数天数也将得到正确处理。  fromIso8601从ISO 8601 日期创建新实例。
        //   startTime: Cesium.JulianDate.fromIso8601('2025-06-03'), //时钟的开始时间
        //   currentTime: Cesium.JulianDate.fromIso8601('2025-06-03'), //当前时间
        //   stopTime: Cesium.JulianDate.fromIso8601('2025-06-04'), //时钟的停止时间。
        //   clockRange: Cesium.ClockRange.LOOP_STOP, //指定时钟的循环范围。
        //   clockStep: Cesium.ClockStep.SYSTEM_CLOCK_MULTIPLIER,
        // }),
      ),
      timeline: true, //是否显示时间线控件
      selectionIndicator: false, //选中实例提示框  点线面绿框
      fullscreenButton: false, //是否全屏显示
      navigationHelpButton: false, //是否显示帮助信息控件
      infoBox: true, //解决无效报错  //是否显示点击要素之后显示的信息
    })
    // viewerCesium.value.scene.globe.enableLighting = true //地球光照
    // viewerCesium.value.clock.clockRange = Cesium.ClockRange.LOOP_STOP // 反复循环
    // viewerCesium.value.clock.multiplier = 5000 // 时间倍速

    //#endregion

    //二、不推荐绑定监听器利用viewer.camera.flyTo实现Home
    //#region
    //cesiumViewer.value.homeButton HOME单按钮小部件，用于返回当前场景的默认相机视图。
    //.viewModel获取视图模型。
    //.command 获取单击按钮时执行的命令。
    //.beforeExecute 获取在命令执行之前引发的事件，该事件使用包含两个属性的对象引发: cancel 属性，如果侦听器将其设置为false，则会阻止命令执行
    // cesiumViewer.value.homeButton.viewModel.command.beforeExecute.addEventListener(function (e) {
    //   e.cancel = true //不阻止命令执行
    //   flyToDefault()
    // })
    // #endregion
  }

  // 飞行到默认位置
  const flyToDefault = () => {
    if (!viewerCesium.value) return
    // /fromDegrees 根据以度为单位给出的经度和纬度值返回 Cartesian3 位置
    const position = Cesium.Cartesian3.fromDegrees(116.39, 39.91, 8000) //飞行目的地
    viewerCesium.value.camera.flyTo({
      //destination目的地
      destination: position, //Type类型 ：Cartesian3 | Rectangle
      //方向
      orientation: {
        //toRadians  以弧度表示对应的角度
        heading: Cesium.Math.toRadians(0), // 摇头，水平旋转，围绕Y轴，0为正北方向
        pitch: Cesium.Math.toRadians(-90), // 点头，上下旋转，围绕X轴，-90为俯视地面
        roll: Cesium.Math.toRadians(0), // 歪头，视口的翻滚角度，围绕Z轴，0为不翻转
      },
      duration: 3, // 飞行时间
    })
  }

  // 销毁 viewer
  const destroyViewerCesium = () => {
    if (viewerCesium.value) {
      viewerCesium.value.destroy()
      viewerCesium.value = null
    }
  }

  return {
    viewerCesium,
    initViewerCesium,
    flyToDefault,
    destroyViewerCesium,
  }
})
